package iconSwingStates.Device;

import iconSwingStates.Event.EVirtualConPositionEvent;
import iconSwingStates.Event.EVirtualIConEvent;
import iconSwingStates.StateMachine.InSwingStates;
import iconSwingStates.StateMachine.SMIconStateMachine;
import iconSwingStates.Transitions.TDrag;
import iconSwingStates.Transitions.TGeneric;
import iconSwingStates.Transitions.TPosition;
import iconSwingStates.Transitions.TPress;
import iconSwingStates.Transitions.TRelease;
import iconSwingStates.Transitions.TSlot;
import iconSwingStates.Transitions.TTransition;
import iconSwingStates.Transitions.TTyped;
import iconSwingStates.Transitions.TransitionOnTag.TActionOnTag;
import iconSwingStates.Transitions.TransitionOnTag.TDragOnTag;
import iconSwingStates.Transitions.TransitionOnTag.TEnterOnTag;
import iconSwingStates.Transitions.TransitionOnTag.TLeaveOnTag;
import iconSwingStates.Transitions.TransitionOnTag.TMoveOnTag;
import iconSwingStates.Transitions.TransitionOnTag.TPressOnTag;
import iconSwingStates.Transitions.TransitionOnTag.TReleaseOnTag;
import iconSwingStates.Transitions.TransitionOnTag.TTypedOnTag;

import java.awt.Point;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.LinkedList;
import java.util.Vector;

import javax.swing.JFrame;
import javax.swing.SwingUtilities;

import fr.emn.reactiveinput.AbstractDevice;
import fr.emn.reactiveinput.Device;
import fr.emn.reactiveinput.DeviceUtilities;
import fr.emn.reactiveinput.In;
import fr.emn.reactiveinput.OpenContext;
import fr.emn.reactiveinput.Processor;
import fr.emn.reactiveinput.SlotType;
import fr.lri.swingstates.canvas.CShape;
import fr.lri.swingstates.canvas.Canvas;
import fr.lri.swingstates.sm.State;
import fr.lri.swingstates.sm.Transition;

/**
 * This class is the translation of a CStateMachine into a Device
 * @author uribe - gaget
 * 
 */
public class DSwingStatesDevice extends AbstractDevice {
	private SMIconStateMachine sm;
	private ArrayList<InSwingStates> slot_ins = new ArrayList<InSwingStates>();
	private JFrame appFrame;
	private Hashtable<String, In> in_pointer = new Hashtable<String, In>();
	private CShape tagged = null;
	private String usedTag = "";
	private boolean useState = false;
	boolean useTmp = false;
	Point2D p_tmp;
	/**
	 * Empty construtor for ICon
	 */
	public DSwingStatesDevice() {
		this("", null);
	}

	/**
	 * Default constructor
	 * 
	 * @param name device's name
	 * @param sm the state machine
	 */
	public DSwingStatesDevice(String name, SMIconStateMachine sm) {
		super(name);
		this.sm = sm;
		setInfo("Swingstates generic device",
				"Use this device to process transitions into " + name);
		setSlots();
	}

	/*
	 * This method is used to manage transitions with multiples slots.
	 */
	private InSwingStates addMultiplesSlots(String pointer, InSwingStates inSS){
		int[] types = inSS.getTransition().getSourcesTypes();
		if(types != null){
			String device="";
			//We manage each type of transition separately. We use the ICon hierarchies in slots' names to classify the transitions
			if ((inSS.getTransition() instanceof TSlot )){
				device=inSS.getTransition().getInputState().getName()+"."+inSS.getName();
			}else{device=pointer+"."+inSS.getName();}	
			if (types.length == 1) {
				// We create the slot. It will be obligatory because it's present in the transition
				boolean doesntExists=true;
				In in = null;
				for(int i=0;i<getIns().length;i++){
					if(device.compareTo(getIns()[i].getName())==0 && types[0] ==getIns()[i].getType()){
						doesntExists=false;
						in = getIns()[i];
					}
				}
				if (doesntExists){
					in = addIn(device, types[0],inSS.getTransition().isObligatory());
				}
				inSS.addIn(in);
			} else {
				//If this transition uses more than one slots, we add as many as it needs and name them accordingly with the transition's name
				for (int index = 0; index < types.length; index++) {
					boolean doesntExists=true;
					In in = null;
					for(int i=0;i<getIns().length;i++){
						if(device.compareTo(getIns()[i].getName())==0 && types[index] ==getIns()[i].getType()){
							doesntExists=false;
							in = getIns()[i];
						}
					}
					if (doesntExists){
						in = addIn(device, types[index],inSS.getTransition().isObligatory());
					}
					inSS.addIn(in);
				}
			}
		}
		return inSS;
	}

	/*
	 * This method create as many slots as needed by the content of every states of the state machine
	 * It also stores the transitions AND the slots in InSwingStates containers.
	 */
	private void setSlots() {
		Vector<State> states = sm.getAllStates();
		for (int s = 0; s < states.size(); s++) {
			LinkedList<Transition> transitions = states.get(s).getTransitions();
			for (int t = 0; t < transitions.size(); t++) {
				// If and only if it's an ICon transition, we create at least one slot per transition, with an exception for the transitions where slots are needless
				if (transitions.get(t) instanceof TGeneric) {
					if(transitions.get(t) instanceof TPress){
						TPress transition = (TPress) transitions.get(t);
						InSwingStates inSS = new InSwingStates(transition);
						slot_ins.add(addMultiplesSlots(transition.getPointer(),inSS));
					}
					else if(transitions.get(t) instanceof TRelease){
						TRelease transition = (TRelease) transitions.get(t);
						InSwingStates inSS = new InSwingStates(transition);
						slot_ins.add(addMultiplesSlots(transition.getPointer(),inSS));				
					}
					else if(transitions.get(t) instanceof TTyped){
						TTyped transition = (TTyped) transitions.get(t);
						InSwingStates inSS = new InSwingStates(transition);
						slot_ins.add(addMultiplesSlots(transition.getPointer(),inSS));						
					}
					else if(transitions.get(t) instanceof TDrag){
						TDrag transition = (TDrag) transitions.get(t);
						InSwingStates inSS = new InSwingStates(transition);
						slot_ins.add(addMultiplesSlots(transition.getPointer(),inSS));	
					}
					else if(transitions.get(t) instanceof TSlot){
						TSlot transition = (TSlot) transitions.get(t);
						InSwingStates inSS = new InSwingStates(transition);
						slot_ins.add(addMultiplesSlots(states.get(s).getName(),inSS));				
					}
					else if(transitions.get(t) instanceof TEnterOnTag){
						TEnterOnTag transition = (TEnterOnTag) transitions.get(t);
						InSwingStates inSS = new InSwingStates(transition);
						slot_ins.add(addMultiplesSlots(states.get(s).getName(),inSS));	

					}
					else if(transitions.get(t) instanceof TLeaveOnTag){
						TLeaveOnTag transition = (TLeaveOnTag) transitions.get(t);
						InSwingStates inSS = new InSwingStates(transition);
						slot_ins.add(addMultiplesSlots(states.get(s).getName(),inSS));	

					}
					else if(transitions.get(t) instanceof TDragOnTag){
						TDragOnTag transition = (TDragOnTag) transitions.get(t);
						InSwingStates inSS = new InSwingStates(transition);
						slot_ins.add(addMultiplesSlots(transition.getPointer(),inSS));							
					}
					else if(transitions.get(t) instanceof TTypedOnTag){
						TTypedOnTag transition = (TTypedOnTag) transitions.get(t);
						InSwingStates inSS = new InSwingStates(transition);
						slot_ins.add(addMultiplesSlots(transition.getPointer(),inSS));							
					}
					else if(transitions.get(t) instanceof TPressOnTag){
						TPressOnTag transition = (TPressOnTag) transitions.get(t);
						InSwingStates inSS = new InSwingStates(transition);
						slot_ins.add(addMultiplesSlots(transition.getPointer(),inSS));								
					}
					else if(transitions.get(t) instanceof TReleaseOnTag){
						TReleaseOnTag transition = (TReleaseOnTag) transitions.get(t);
						InSwingStates inSS = new InSwingStates(transition);
						slot_ins.add(addMultiplesSlots(transition.getPointer(),inSS));							
					}
				}
			}
		}
		for(int i = 0; i< sm.getPointers().length;i++){
			In x = addIn(sm.getPointers()[i] + ".x", SlotType.DOUBLE,false);
			in_pointer.put(sm.getPointers()[i]+".x", x);
			In y = addIn(sm.getPointers()[i] + ".y", SlotType.DOUBLE,false);
			in_pointer.put(sm.getPointers()[i]+".y", y);
		}
	}




	@Override
	public boolean hasExternalOutput() {
		return true;
	}

	@Override
	public boolean hasExternalInput() {
		return false;
	}

	@Override
	public Device copy() {
		DSwingStatesDevice copy = new DSwingStatesDevice(getName(), sm);
		copy.setName(getName());
		DeviceUtilities.setPrototype(copy, DeviceUtilities.getPrototype(this));
		DeviceUtilities.copyPropertyValues(this, copy);
		return copy;
	}

	@Override
	public void init() {
		update();
	}

	@Override
	public Processor open(OpenContext context) {
		if (appFrame == null) {
			appFrame = context.getJFrameValue();
		}

		if (appFrame == null) {
			return null;
		}
		return super.open(context);
	}

	/*
	 * This method looks if the transition need synchronized signals and returns a boolean if there are the needed signals on the slots.
	 */
	private boolean haveSignals(InSwingStates slots) {
		if(slots.getIns().size() == 0){
			return true;
		}
		else{
			boolean haveSignals = false;
			if (slots.isSynchro()) {
				boolean b = slots.getIns().get(0).hasSignal();
				for (int i = 0; i < slots.getIns().size(); i++) {
					if (b != slots.getIns().get(i).hasSignal()) {
						return false;
					}
				}
				haveSignals = b;
			} else {
				for (int i = 0; i < slots.getIns().size(); i++) {
					if (slots.getIns().get(i).hasSignal()) {
						return true;
					}
				}
			}
			return haveSignals;
		}
	}


	/*
	 * This method looks if the transition need synchronized values and returns a boolean if there are the needed values on the slots.
	 */
	private boolean haveValues(InSwingStates slots) {
		if(slots.getIns().size() == 0){
			return true;
		}
		else{
			boolean haveSignals = false;
			if (slots.isSynchro()) {
				boolean b = slots.getIns().get(0).hasValue();
				for (int i = 0; i < slots.getIns().size(); i++) {
					if (b != slots.getIns().get(i).hasValue()) {
						return false;
					}
				}
				haveSignals = b;
			} else {
				for (int i = 0; i < slots.getIns().size(); i++) {
					if (slots.getIns().get(i).hasValue()) {
						return true;
					}
				}
			}
			return haveSignals;
		}
	}
	
	/*
	 * This method makes all the verifications needed to know if the device must fire the TLeaveOnTag event or not
	 */
	private void processLeaveOnTag(TLeaveOnTag transition){
		for (int i_slot = 0; i_slot < slot_ins.size(); i_slot++) {
			//If the transition is an instance of TLeaveOnTag and we already are over a tagged shape
			if (slot_ins.get(i_slot).getTransition() instanceof TLeaveOnTag && tagged != null && haveSignals(slot_ins.get(i_slot))) {
				TLeaveOnTag t_device = (TLeaveOnTag) slot_ins.get(i_slot).getTransition();
				Canvas c = sm.getCanvas();
				Point p = new Point((int)in_pointer.get(transition.getPointer()+".x").getDoubleValue(), (int)in_pointer.get(transition.getPointer()+".y").getDoubleValue());
				SwingUtilities.convertPointFromScreen(p, c);
				CShape shape = c.pickShapeHavingTag(p,t_device.getTag());
				//If we leaved the shape
				if(shape == null){
					if(transition.equals(t_device) && transition.getTag().compareTo(usedTag)==0){
						ArrayList<Object> values = new ArrayList<Object>();
						for (int i_value = 0; i_value < slot_ins
						.get(i_slot).getIns().size(); i_value++) {
							In in = slot_ins.get(i_slot).getIns().get(
									i_value);
							switch (in.getType()) {
							case SlotType.BOOLEAN:
								values.add(in.getBooleanValue());
								break;
							case SlotType.DOUBLE:
								values.add(in.getDoubleValue());
								break;
							case SlotType.INT:
								values.add(in.getIntValue());
								break;
							case SlotType.OBJECT:
								values.add(in.getObjectValue());
								break;
							case SlotType.STRING:
								values.add(in.getStringValue());
								break;
							}
						}
						tagged = shape;
						usedTag = "";
						transition.setShape(tagged);
						EVirtualConPositionEvent event = new EVirtualConPositionEvent(transition.getName(), p.getX(), p.getY(), values);
						sm.processEvent(event);
					}
				}
				else{
					//If we leave the tagged shape and entered on another one
					if(transition.equals(t_device) && transition.getTag().compareTo(usedTag)==0 && !shape.equals(tagged)){
						tagged = shape;
						usedTag = "";
						transition.setShape(tagged);
						ArrayList<Object> values = new ArrayList<Object>();
						for (int i_value = 0; i_value < slot_ins
						.get(i_slot).getIns().size(); i_value++) {
							In in = slot_ins.get(i_slot).getIns().get(
									i_value);
							switch (in.getType()) {
							case SlotType.BOOLEAN:
								values.add(in.getBooleanValue());
								break;
							case SlotType.DOUBLE:
								values.add(in.getDoubleValue());
								break;
							case SlotType.INT:
								values.add(in.getIntValue());
								break;
							case SlotType.OBJECT:
								values.add(in.getObjectValue());
								break;
							case SlotType.STRING:
								values.add(in.getStringValue());
								break;
							}

						}
						EVirtualConPositionEvent event = new EVirtualConPositionEvent(transition.getName(), p.getX(), p.getY(), values);
						sm.processEvent(event);
					}
				}
			}
		}
	}
	/*
	 * This method makes all the verifications needed to know if the device must fire the TEnterOnTag event or not
	 */
	private void processEnterOnTag(TEnterOnTag transition){
		for (int i_slot = 0; i_slot < slot_ins.size(); i_slot++) {
			//if we have an instance of TEnterOnTAg
			if (slot_ins.get(i_slot).getTransition() instanceof TEnterOnTag && haveSignals(slot_ins.get(i_slot))) {
				TEnterOnTag t_device = (TEnterOnTag) slot_ins.get(i_slot).getTransition();
				Canvas c = sm.getCanvas();
				Point p = new Point((int)in_pointer.get(transition.getPointer()+".x").getDoubleValue(), (int)in_pointer.get(transition.getPointer()+".y").getDoubleValue());
				SwingUtilities.convertPointFromScreen(p, c);
				CShape shape = c.pickShapeHavingTag(p,
						t_device.getTag());
				//If we are over a tagged shape
				if (transition.equals(t_device) && shape != null && !shape.equals(tagged)) {
					//If the tag isn't the right one, we launch a leaveOnTag transition before the enterOnTag one
					if(usedTag.compareTo("") != 0){
						for (int i = 0; i < slot_ins.size(); i++) {
							if (slot_ins.get(i).getTransition() instanceof TLeaveOnTag){
								TLeaveOnTag transition_leave = (TLeaveOnTag)slot_ins.get(i).getTransition() ;
								if(transition_leave.getTag().compareTo(usedTag)==0){
									EVirtualIConEvent event = new EVirtualConPositionEvent(
											transition_leave.getName(),in_pointer.get(transition_leave.getPointer()+".x").getDoubleValue(), in_pointer.get(transition_leave.getPointer()+".y").getDoubleValue());
									sm.processEvent(event);
								}
							}
						}
					}
					tagged = shape;
					ArrayList<Object> values = new ArrayList<Object>();
					for (int i_value = 0; i_value < slot_ins
					.get(i_slot).getIns().size(); i_value++) {
						In in = slot_ins.get(i_slot).getIns().get(
								i_value);
						switch (in.getType()) {
						case SlotType.BOOLEAN:
							values.add(in.getBooleanValue());
							break;
						case SlotType.DOUBLE:
							values.add(in.getDoubleValue());
							break;
						case SlotType.INT:
							values.add(in.getIntValue());
							break;
						case SlotType.OBJECT:
							values.add(in.getObjectValue());
							break;
						case SlotType.STRING:
							values.add(in.getStringValue());
							break;
						}

					}
					usedTag = transition.getTag();
					t_device.setShape(tagged);
					EVirtualConPositionEvent event = new EVirtualConPositionEvent(transition.getName(), p.getX(), p.getY(), values);
					transition.setShape(shape);
					sm.processEvent(event);
				}
			}
		}
	}

	/*
	 * This method makes all the verifications needed to know if the device must fire the TActionOnTag event or not
	 */
	private void processActionOnTag(TActionOnTag transition){
		for (int i_slot = 0; i_slot < slot_ins.size(); i_slot++) {
			if (slot_ins.get(i_slot).getTransition() instanceof TActionOnTag && haveSignals(slot_ins.get(i_slot))) {
				TActionOnTag t_device = (TActionOnTag) slot_ins.get(i_slot).getTransition();
				//If it's the right transition AND the slots have signals, then we verify the tag
				if (transition.equals(t_device)
						&& haveSignals(slot_ins.get(i_slot))) {
					Canvas c = sm.getCanvas();
					Point p = new Point((int) in_pointer.get(transition.getPointer()+".x").getDoubleValue(), 
							(int) in_pointer.get(transition.getPointer()+".y").getDoubleValue());
					SwingUtilities.convertPointFromScreen(p, c);
					CShape shape = c.pickShapeHavingTag(p,t_device.getTag());		
					//If we have a tagged shape then we fire the event
					if (shape != null ) {
						tagged = shape;
						transition.setShape(tagged);
						ArrayList<Object> values = new ArrayList<Object>();
						for (int i_value = 3; i_value < slot_ins
						.get(i_slot).getIns().size(); i_value++) {
							In in = slot_ins.get(i_slot).getIns().get(i_value);
							if(in.hasSignal()){
								switch (in.getType()) {
								case SlotType.BOOLEAN:
									values.add(in.getBooleanValue());
									break;
								case SlotType.DOUBLE:
									values.add(in.getDoubleValue());
									break;
								case SlotType.INT:
									values.add(in.getIntValue());
									break;
								case SlotType.OBJECT:
									values.add(in.getObjectValue());
									break;
								case SlotType.STRING:
									values.add(in.getStringValue());
									break;
								}
							}
							else{
								values.add(null);
							}
						}
						EVirtualConPositionEvent event = new EVirtualConPositionEvent(transition.getName(), p.getX(), p.getY(), values);
						sm.processEvent(event);
					}
				}
			}
		}
	}

	/*
	 * This method makes all the verifications needed to know if the device must fire the TMoveOnTag event or not
	 */
	private void processMoveOnTag(TMoveOnTag transition){
		for (int i_slot = 0; i_slot < slot_ins.size(); i_slot++) {
			if (slot_ins.get(i_slot).getTransition() instanceof TMoveOnTag && haveSignals(slot_ins.get(i_slot))) {
				TMoveOnTag t_device = (TMoveOnTag) slot_ins
				.get(i_slot).getTransition();
				Canvas c = sm.getCanvas();
				Point p_shape = new Point((int)in_pointer.get(transition.getPointer()+".x").getDoubleValue(), (int)in_pointer.get(transition.getPointer()+".y").getDoubleValue());
				SwingUtilities.convertPointFromScreen(p_shape, c);
				CShape shape = c.pickShapeHavingTag(p_shape,t_device.getTag());
				if (transition.equals(t_device)	&& shape != null) {	
					transition.setShape(tagged);

					ArrayList<Object> values = new ArrayList<Object>();
					for (int i_value = 0; i_value < slot_ins
					.get(i_slot).getIns().size(); i_value++) {
						In in = slot_ins.get(i_slot).getIns().get(
								i_value);
						switch (in.getType()) {
						case SlotType.BOOLEAN:
							values.add(in.getBooleanValue());
							break;
						case SlotType.DOUBLE:
							values.add(in.getDoubleValue());
							break;
						case SlotType.INT:
							values.add(in.getIntValue());
							break;
						case SlotType.OBJECT:
							values.add(in.getObjectValue());
							break;
						case SlotType.STRING:
							values.add(in.getStringValue());
							break;
						}

					}

					EVirtualConPositionEvent event = new EVirtualConPositionEvent(transition.getName(), p_shape.getX(), p_shape.getY(), values);
					sm.processEvent(event);

				}
			}
		}
	}

	/*
	 * This method makes all the verifications needed to know if the device must fire the TTypedOnTag event or not
	 */
	private void processClickOnTag(TTypedOnTag transition){
		for (int i_slot = 0; i_slot < slot_ins.size(); i_slot++) {
			if(slot_ins.get(i_slot).getTransition()instanceof TTypedOnTag && haveSignals(slot_ins.get(i_slot))){
				TTypedOnTag t_device = (TTypedOnTag)slot_ins.get(i_slot).getTransition();
				Canvas c = sm.getCanvas();
				Point p_shape = new Point((int)in_pointer.get(transition.getPointer()+".x").getDoubleValue(), (int)in_pointer.get(transition.getPointer()+".y").getDoubleValue());
				SwingUtilities.convertPointFromScreen(p_shape, c);
				CShape shape = c.pickShapeHavingTag(p_shape,t_device.getTag());
				if (transition.equals(t_device)&& haveSignals(slot_ins.get(i_slot)) && (shape != null)) {					
					Point2D p=new Point2D.Double(0,0);
					if (!transition.getPointer().equals("")){
						p = new Point2D.Double(in_pointer.get(transition.getPointer()+".x").getDoubleValue(),in_pointer.get(transition.getPointer()+".y").getDoubleValue());
					}
					if(useState && !useTmp && (transition.getPointer().equals("") || p_tmp.distance(p) < 2)){
						ArrayList<Object> values = new ArrayList<Object>();
						for (int i_value = 0; i_value < slot_ins
						.get(i_slot).getIns().size(); i_value++) {
							In in = slot_ins.get(i_slot).getIns().get(
									i_value);
							switch (in.getType()) {
							case SlotType.BOOLEAN:
								values.add(in.getBooleanValue());
								break;
							case SlotType.DOUBLE:
								values.add(in.getDoubleValue());
								break;
							case SlotType.INT:
								values.add(in.getIntValue());
								break;
							case SlotType.OBJECT:
								values.add(in.getObjectValue());
								break;
							case SlotType.STRING:
								values.add(in.getStringValue());
								break;
							}

						}
						transition.setShape(shape);
						EVirtualIConEvent event = new EVirtualIConEvent(
								transition.getName(), values);
						sm.processEvent(event);
						useTmp = false;
						useState = false;
					}
					else if(!useState && !useTmp){
						if(slot_ins.get(i_slot).getIns().get(0).getBooleanValue()){
							useState = true;
							if (!transition.getPointer().equals(""))
								p_tmp = new Point2D.Double(in_pointer.get(transition.getPointer()+".x").getDoubleValue(),in_pointer.get(transition.getPointer()+".y").getDoubleValue());
						}
					}
					else{
						useTmp = false;
						useState = false;					
					}
				}
			}
		}
	}
	/*
	 * This method makes all the verifications needed to know if the device must fire the TPressOnTag event or not
	 */
	private void processPressOnTag(TPressOnTag transition){
		if(!useState){			
			for (int i_slot = 0; i_slot < slot_ins.size(); i_slot++) {
				if(slot_ins.get(i_slot).getTransition()instanceof TPressOnTag && haveSignals(slot_ins.get(i_slot))){
					TPressOnTag t_device = (TPressOnTag)slot_ins.get(i_slot).getTransition();
					String pointer = t_device.getPointer();
					Canvas c = sm.getCanvas();
					Point p = new Point((int)in_pointer.get(transition.getPointer()+".x").getDoubleValue(), (int)in_pointer.get(transition.getPointer()+".y").getDoubleValue());
					SwingUtilities.convertPointFromScreen(p, c);
					CShape shape = c.pickShapeHavingTag(p,t_device.getTag());
					if (transition.equals(t_device)&& haveSignals(slot_ins.get(i_slot)) && shape != null) {
						if(slot_ins.get(i_slot).getIns().get(0).getBooleanValue()){
							ArrayList<Object> values = new ArrayList<Object>();
							for (int i_value = 1; i_value < slot_ins.get(i_slot).getIns().size(); i_value++) {


								In in = slot_ins.get(i_slot).getIns().get(
										i_value);
								switch (in.getType()) {
								case SlotType.BOOLEAN:
									values.add(in.getBooleanValue());
									break;
								case SlotType.DOUBLE:
									values.add(in.getDoubleValue());
									break;
								case SlotType.INT:
									values.add(in.getIntValue());
									break;
								case SlotType.OBJECT:
									values.add(in.getObjectValue());
									break;
								case SlotType.STRING:
									values.add(in.getStringValue());
									break;
								}

							}
							EVirtualConPositionEvent event = new EVirtualConPositionEvent(transition.getName(), p.getX(), p.getY(), values);
							sm.processEvent(event);
							useState = true;				
						}
					}
				}

			}
		}
	}
	/*
	 * This method makes all the verifications needed to know if the device must fire the TReleaseOnTag event or not
	 */
	private void processReleaseOnTag(TReleaseOnTag transition){
		if(useState){
			for (int i_slot = 0; i_slot < slot_ins.size(); i_slot++) {
				if(slot_ins.get(i_slot).getTransition() instanceof TReleaseOnTag){
					TReleaseOnTag t_device = (TReleaseOnTag)slot_ins.get(i_slot).getTransition();	
					String pointer = t_device.getPointer();
					Canvas c = sm.getCanvas();
					Point p = new Point((int)in_pointer.get(transition.getPointer()+".x").getDoubleValue(), (int)in_pointer.get(transition.getPointer()+".y").getDoubleValue());
					SwingUtilities.convertPointFromScreen(p, c);
					CShape shape = c.pickShapeHavingTag(p,t_device.getTag());
					if (transition.equals(t_device)&& haveSignals(slot_ins.get(i_slot)) && shape != null) {
						if(!slot_ins.get(i_slot).getIns().get(0).getBooleanValue()){
							ArrayList<Object> values = new ArrayList<Object>();
							for (int i_value = 0; i_value < slot_ins
							.get(i_slot).getIns().size(); i_value++) {
								In in = slot_ins.get(i_slot).getIns().get(
										i_value);
								switch (in.getType()) {
								case SlotType.BOOLEAN:
									values.add(in.getBooleanValue());
									break;
								case SlotType.DOUBLE:
									values.add(in.getDoubleValue());
									break;
								case SlotType.INT:
									values.add(in.getIntValue());
									break;
								case SlotType.OBJECT:
									values.add(in.getObjectValue());
									break;
								case SlotType.STRING:
									values.add(in.getStringValue());
									break;
								}

							}
							EVirtualConPositionEvent event = new EVirtualConPositionEvent(transition.getName(), p.getX(), p.getY(), values);
							sm.processEvent(event);
							useState = false;
						}
					}
				}
			}
		}
	}
	/*
	 * This method makes all the verifications needed to know if the device must fire the TRelease event or not
	 */
	private void processRelease(TRelease transition){
		if(useState){
			for (int i_slot = 0; i_slot < slot_ins.size(); i_slot++) {
				TGeneric t_device = slot_ins.get(i_slot).getTransition();
				if (transition.equals(t_device)&& haveSignals(slot_ins.get(i_slot))) {
					if(!slot_ins.get(i_slot).getIns().get(0).getBooleanValue()){
						ArrayList<Object> values = new ArrayList<Object>();
						for (int i_value = 0; i_value < slot_ins
						.get(i_slot).getIns().size(); i_value++) {
							In in = slot_ins.get(i_slot).getIns().get(
									i_value);
							switch (in.getType()) {
							case SlotType.BOOLEAN:
								values.add(in.getBooleanValue());
								break;
							case SlotType.DOUBLE:
								values.add(in.getDoubleValue());
								break;
							case SlotType.INT:
								values.add(in.getIntValue());
								break;
							case SlotType.OBJECT:
								values.add(in.getObjectValue());
								break;
							case SlotType.STRING:
								values.add(in.getStringValue());
								break;
							}
						}
						EVirtualIConEvent event = new EVirtualIConEvent(
								transition.getName(), values);
						sm.processEvent(event);
						useState = false;
					}
				}
			}
		}
	}
	/*
	 * This method makes all the verifications needed to know if the device must fire the TPress event or not
	 */
	private void processPress(TPress transition){
		if(!useState){
			for (int i_slot = 0; i_slot < slot_ins.size(); i_slot++) {
				TGeneric t_device = slot_ins.get(i_slot).getTransition();
				if (transition.equals(t_device)&& haveSignals(slot_ins.get(i_slot))) {
					if(slot_ins.get(i_slot).getIns().get(0).getBooleanValue()){
						ArrayList<Object> values = new ArrayList<Object>();
						for (int i_value = 0; i_value < slot_ins
						.get(i_slot).getIns().size(); i_value++) {
							In in = slot_ins.get(i_slot).getIns().get(
									i_value);
							switch (in.getType()) {
							case SlotType.BOOLEAN:
								values.add(in.getBooleanValue());
								break;
							case SlotType.DOUBLE:
								values.add(in.getDoubleValue());
								break;
							case SlotType.INT:
								values.add(in.getIntValue());
								break;
							case SlotType.OBJECT:
								values.add(in.getObjectValue());
								break;
							case SlotType.STRING:
								values.add(in.getStringValue());
								break;
							}
						}
						EVirtualIConEvent event = new EVirtualIConEvent(
								transition.getName(), values);
						sm.processEvent(event);
						useState = true;
					}
				}
			}
		}
	}
	/*
	 * This method makes all the verifications needed to know if the device must fire the TTyped event or not. We have to make the verifications in 3 steps :
	 *  - Initial state, no button pressed
	 *  - The button is pressed
	 *  - The button is released, we fire the event.
	 */
	private void processClick(TTyped transition){
		for (int i_slot = 0; i_slot < slot_ins.size(); i_slot++) {
			TGeneric t_device = slot_ins.get(i_slot).getTransition();
			if (transition.equals(t_device) && haveSignals(slot_ins.get(i_slot))) {
				Point2D p=new Point2D.Double(0,0);
				if (!transition.getPointer().equals(""))
					p = new Point2D.Double(in_pointer.get(transition.getPointer()+".x").getDoubleValue(),in_pointer.get(transition.getPointer()+".y").getDoubleValue());
				if(useState && !useTmp && (transition.getPointer().equals("") || p_tmp.distance(p) < 2)){
					ArrayList<Object> values = new ArrayList<Object>();
					for (int i_value = 0; i_value < slot_ins
					.get(i_slot).getIns().size(); i_value++) {
						In in = slot_ins.get(i_slot).getIns().get(
								i_value);
						switch (in.getType()) {
						case SlotType.BOOLEAN:
							values.add(in.getBooleanValue());
							break;
						case SlotType.DOUBLE:
							values.add(in.getDoubleValue());
							break;
						case SlotType.INT:
							values.add(in.getIntValue());
							break;
						case SlotType.OBJECT:
							values.add(in.getObjectValue());
							break;
						case SlotType.STRING:
							values.add(in.getStringValue());
							break;
						}
					}
					EVirtualIConEvent event = new EVirtualIConEvent(
							transition.getName(), values);
					sm.processEvent(event);
					useTmp = false;
					useState = false;
				}
				else if(!useState && !useTmp){
					if(slot_ins.get(i_slot).getIns().get(0).getBooleanValue()){
						useState = true;
						if (!transition.getPointer().equals(""))
							p_tmp = new Point2D.Double(in_pointer.get(transition.getPointer()+".x").getDoubleValue(),in_pointer.get(transition.getPointer()+".y").getDoubleValue());
					}
				}
				else{
					useTmp = false;
					useState = false;					
				}
			}
		}
	}
	/*
	 * This method makes all the verifications needed to know if the device must fire the TPosition event or not
	 */
	private void processPositionTransition(TPosition transition){
		for (int i_slot = 0; i_slot < slot_ins.size(); i_slot++) {
			if (slot_ins.get(i_slot).getTransition() instanceof TPosition && haveSignals(slot_ins.get(i_slot))) {
				TPosition t_device = (TPosition) slot_ins
				.get(i_slot).getTransition();
				if (transition.equals(t_device)	&& haveSignals(slot_ins.get(i_slot))) {
					ArrayList<Object> values = new ArrayList<Object>();
					for (int i_value = 0; i_value < slot_ins.get(i_slot).getIns().size(); i_value++) {
						In in = slot_ins.get(i_slot).getIns().get(i_value);
						switch (in.getType()) {
						case SlotType.BOOLEAN:
							values.add(in.getBooleanValue());
							break;
						case SlotType.DOUBLE:
							values.add(in.getDoubleValue());
							break;
						case SlotType.INT:
							values.add(in.getIntValue());
							break;
						case SlotType.OBJECT:
							values.add(in.getObjectValue());
							break;
						case SlotType.STRING:
							values.add(in.getStringValue());
							break;
						}
					}
					String pointer = transition.getPointer();
					EVirtualConPositionEvent event =  new EVirtualConPositionEvent(
							transition.getName(), in_pointer.get(pointer+".x").getDoubleValue(), in_pointer.get(pointer+".y").getDoubleValue(),values);
					sm.processEvent(event);
				}
			}
		}
	}


	//TODO !!! havesignals
	/*
	 * This method makes all the verifications needed to know if the device must fire the TDrag event or not
	 */
	private void processDrag(TDrag transition){
		if(useState){
			String pointer = transition.getPointer();
			for (int i_slot = 0; i_slot < slot_ins.size(); i_slot++) {
				if (slot_ins.get(i_slot).getTransition() instanceof TDrag){// &&  haveValues(slot_ins.get(i_slot))) {	
					if (in_pointer.get(pointer+".x").hasSignal() || in_pointer.get(pointer+".y").hasSignal()) {
						ArrayList<Object> values = new ArrayList<Object>();
						for (int i_value = 0; i_value < slot_ins.get(i_slot).getIns().size(); i_value++) {
							In in = slot_ins.get(i_slot).getIns().get(i_value);
							switch (in.getType()) {
							case SlotType.BOOLEAN:
								values.add(in.getBooleanValue());
								break;
							case SlotType.DOUBLE:
								values.add(in.getDoubleValue());
								break;
							case SlotType.INT:
								values.add(in.getIntValue());
								break;
							case SlotType.OBJECT:
								values.add(in.getObjectValue());
								break;
							case SlotType.STRING:
								values.add(in.getStringValue());
								break;
							}
						}
						EVirtualConPositionEvent event =  new EVirtualConPositionEvent(
								transition.getName(), in_pointer.get(pointer+".x").getDoubleValue(), in_pointer.get(pointer+".y").getDoubleValue(),values);
						sm.processEvent(event);
					}
				}
			}
		}
	}
	/*
	 * This method makes all the verifications needed to know if the device must fire the TDragOnTag event or not
	 */
	private void processDragOnTag(TDragOnTag transition){
		if(useState){
			String pointer = transition.getPointer();
			for (int i_slot = 0; i_slot < slot_ins.size(); i_slot++) {
				if (slot_ins.get(i_slot).getTransition() instanceof TDragOnTag ){//&& haveSignals(slot_ins.get(i_slot))) {	
					TDragOnTag t_device = (TDragOnTag)slot_ins.get(i_slot).getTransition();
					Canvas c = sm.getCanvas();
					Point p = new Point((int)in_pointer.get(transition.getPointer()+".x").getDoubleValue(), (int)in_pointer.get(transition.getPointer()+".y").getDoubleValue());
					SwingUtilities.convertPointFromScreen(p, c);
					CShape shape = c.pickShapeHavingTag(p,t_device.getTag());
					if (in_pointer.get(pointer+".x").hasSignal() || in_pointer.get(pointer+".y").hasSignal() && shape != null) {
						ArrayList<Object> values = new ArrayList<Object>();
						for (int i_value = 0; i_value < slot_ins.get(i_slot).getIns().size(); i_value++) {
							In in = slot_ins.get(i_slot).getIns().get(i_value);
							switch (in.getType()) {
							case SlotType.BOOLEAN:
								values.add(in.getBooleanValue());
								break;
							case SlotType.DOUBLE:
								values.add(in.getDoubleValue());
								break;
							case SlotType.INT:
								values.add(in.getIntValue());
								break;
							case SlotType.OBJECT:
								values.add(in.getObjectValue());
								break;
							case SlotType.STRING:
								values.add(in.getStringValue());
								break;
							}
						}
						EVirtualConPositionEvent event = new EVirtualConPositionEvent(transition.getName(), p.getX(),p.getY(), values);
						sm.processEvent(event);
					}
				}
			}
		}
	}

	/*
	 * This method makes all the verifications needed to know if the device must fire the TGeneric event or not
	 */
	private void processVirtualTransition(TGeneric transition){
		for (int i_slot = 0; i_slot < slot_ins.size(); i_slot++) {
			TGeneric t_device = slot_ins.get(i_slot).getTransition();
			if (transition.equals(t_device)
					&& haveSignals(slot_ins.get(i_slot))) {
				ArrayList<Object> values = new ArrayList<Object>();
				for (int i_value = 0; i_value < slot_ins
				.get(i_slot).getIns().size(); i_value++) {
					In in = slot_ins.get(i_slot).getIns().get(
							i_value);
					switch (in.getType()) {
					case SlotType.BOOLEAN:
						values.add(in.getBooleanValue());
						break;
					case SlotType.DOUBLE:
						values.add(in.getDoubleValue());
						break;
					case SlotType.INT:
						values.add(in.getIntValue());
						break;
					case SlotType.OBJECT:
						values.add(in.getObjectValue());
						break;
					case SlotType.STRING:
						values.add(in.getStringValue());
						break;
					}
				}
				EVirtualIConEvent event = new EVirtualIConEvent(
						transition.getName(), values);
				sm.processEvent(event);
			}
		}
	}

	@Override
	public void update() {
		//We get all the transitions of the current state
		LinkedList<Transition> transitions_machine = sm.getCurrentState()
		.getTransitions();
		//Depending of the kind of transition, we will call another method to process the informations.
		for (int i_machine = 0; i_machine < transitions_machine.size(); i_machine++) {
			// TRANSITION ONTAG
			//EnterOnTag
			if (transitions_machine.get(i_machine) instanceof TEnterOnTag) {
				TEnterOnTag transition = (TEnterOnTag)transitions_machine.get(i_machine);
				processEnterOnTag(transition);	

			} else if (transitions_machine.get(i_machine) instanceof TLeaveOnTag && tagged != null) {
				//LeaveOnTag
				TLeaveOnTag transition = (TLeaveOnTag) transitions_machine.get(i_machine);
				processLeaveOnTag(transition);		
			}  else if (transitions_machine.get(i_machine) instanceof TTypedOnTag) {
				//LeaveOnTag
				TTypedOnTag transition = (TTypedOnTag) transitions_machine.get(i_machine);
				processClickOnTag(transition);		
			}   else if (transitions_machine.get(i_machine) instanceof TDragOnTag) {
				//LeaveOnTag
				TDragOnTag transition = (TDragOnTag) transitions_machine.get(i_machine);
				processDragOnTag(transition);		
			}  else if (transitions_machine.get(i_machine) instanceof TPressOnTag) {
				//LeaveOnTag
				TPressOnTag transition = (TPressOnTag) transitions_machine.get(i_machine);
				processPressOnTag(transition);		
			} else if (transitions_machine.get(i_machine) instanceof TReleaseOnTag) {
				//LeaveOnTag
				TReleaseOnTag transition = (TReleaseOnTag) transitions_machine.get(i_machine);
				processReleaseOnTag(transition);		
			} else if (transitions_machine.get(i_machine) instanceof TDrag) {
				//Drag
				TDrag transition = (TDrag) transitions_machine.get(i_machine);
				processDrag(transition);	
			} else if (transitions_machine.get(i_machine) instanceof TActionOnTag) {
				//Drag
				TActionOnTag transition = (TActionOnTag) transitions_machine.get(i_machine);
				processActionOnTag(transition);	
			} else if (transitions_machine.get(i_machine) instanceof TMoveOnTag) {
				//MoveOnTag
				TMoveOnTag transition = (TMoveOnTag) transitions_machine.get(i_machine);
				processMoveOnTag(transition);						
			}
			else if (transitions_machine.get(i_machine) instanceof TPosition){
				// PositionTransition
				TPosition transition = (TPosition) transitions_machine.get(i_machine);
				processPositionTransition(transition);					
			}	
			//Transition Press simple
			else if (transitions_machine.get(i_machine) instanceof TPress) {
				// C'est une transition d'ICon
				TPress transition = (TPress) transitions_machine
				.get(i_machine);
				processPress(transition);
			}
			//Transition Press simple
			else if (transitions_machine.get(i_machine) instanceof TRelease) {
				// C'est une transition d'ICon
				TRelease transition = (TRelease) transitions_machine
				.get(i_machine);
				processRelease(transition);
			}
			//Transition Press simple
			else if (transitions_machine.get(i_machine) instanceof TTyped) {
				// C'est une transition d'ICon
				TTyped transition = (TTyped) transitions_machine
				.get(i_machine);
				processClick(transition);
			}
			//Transition simple
			else if (transitions_machine.get(i_machine) instanceof TGeneric) {
				// C'est une transition d'ICon
				TGeneric transition = (TGeneric) transitions_machine
				.get(i_machine);
				processVirtualTransition(transition);
			}
		}
	}


}